package finalgame.GUI.battle;

import org.lwjgl.input.Keyboard;
import org.newdawn.slick.UnicodeFont;
import org.newdawn.slick.opengl.Texture;

import finalgame.Game;
import finalgame.Engine.Battle;
import finalgame.Engine.HealPokemon;
import finalgame.Engine.pokemon.Pokemon;
import finalgame.Engine.trainer.Trainer;
import finalgame.Engine.trainer.trainerBoss;
import finalgame.GUI.TextMenu;
import finalgame.Graphics.GraphicsConstants;
import finalgame.Graphics.Location;
import finalgame.Graphics.RenderEngine;
import finalgame.Graphics.RenderObj;

public class BattleMenu extends TextMenu {
	private int state;
	private final int MAIN = -1;
	private final int SEL_ATTACK = 0;
	private final int SEL_POKEMON = 1;
	private final int CATCH = 2;
	private final int FLEE = 3;
	private String[] attacks;
	private String[] pokemon;
	private final String[] mainButtons = { "Attack", "Pokemon", "Catch", "Flee" };
	private String currentName;
	private String myName;
	private Trainer me;
	private BattleScreen parent;
	private boolean exit;
	private int default_attack;
	
	/**
	 * @param me The player
	 * @param parent The parent battle
	 */
	public BattleMenu(Trainer me, BattleScreen parent) {
		attacks = me.getCurrentPokemon().getMoves();
		currentName = me.getCurrentPokemon().getClass().getSimpleName();
		strings = mainButtons;
		currentTitle = "What should " + currentName + " do?";
		pokemon = extractPokemon(me);
		this.me = me;
		myName = me.getName();
		state = MAIN;
		this.parent = parent;
		// Find the location to render the first line of text
		// 1. Find the render location of the battle
		baseLoc = parent.getRenderLocation();
		// 2. Get the texture for the battle
		String name = parent.getClass().getSimpleName().toLowerCase();
		Texture tex = RenderEngine.getSprite(name + ".bg");
		// 3. Shift location over to 20 px further than right end of texture
		baseLoc.x(baseLoc.x() + tex.getImageWidth() + 20);
	}
	
	/**
	 * Extract pokemon from trainer
	 * @param me
	 * @return An array of the names of all the 
	 */
	private String[] extractPokemon(Trainer me) {
		Pokemon[] tp = me.getPokemonInventory();
		int size = getSize(tp);
		String[] names = new String[tp.length];
		for(int i = 0; i < size; i++) {
			names[i] = tp[i].getClass().getSimpleName();
		}
		return names;
	}
	
	/**
	 * Get size of array (assuming that there are no null elements before last actual element)
	 * @return logical size of array (or at least "Safe" size)
	 */
	private<T> int getSize(T[] array) { 
		for(int i = 0; i < array.length; i++)
			if(array[i] == null) return i;
		return array.length;
	}
	
	/**
	 * Move to selected menu
	 * @param which Which menu to move to
	 */
	private void moveTo(int which) {
		state = which;
		switch(state) {
		case SEL_ATTACK:
			strings = attacks;
			sel_index = default_attack;
			break;
		case SEL_POKEMON:
			currentTitle = "What pokemon?";
			strings = pokemon;
			break;
		case CATCH:
			tryCatch();
			returnToMain();
			break;
		case FLEE:
			tryFlee();
			break;
		}
	}
	
	private void tryFlee() {
		if(parent.getBattle() != null) {
			if(!(parent.getBattle().getOpponent() == null) &&
					parent.getBattle().checkState() == 0) {
				Game.say("You can't run from a trainer battle.", "Alert");
				returnToMain();
			} else if(parent.getBattle().canFlee()) {
				exit = true;
				key_down = -30;
				Game.say("Got away safely!", "Alert");
			} else {
				String s = parent.getBattle().performAction("flee");
				if(s != null) Game.say(s, "Alert");
				returnToMain();
			}
		}
	}
	
	private void healAll() {
		HealPokemon.healPokemon(parent.getBattle().getMe());
		if(parent.getBattle().getOpponent() != null)
			HealPokemon.healPokemon(parent.getBattle().getOpponent());
		else
			HealPokemon.healPokemon(parent.getBattle().getOpponentPokemon());
	}
	
	private void lose() {
		healAll();
		Game.exit();
		Game.losing();
	}
	
	private void win() {
		healAll();
		Game.exit();
		Game.winning();
	}
	
	private void tryCatch() {
		String s = parent.getBattle().performAction("catch");
		if(s != null) Game.say(s, "Alert");
	}
	
	/**
	 * Use selected attack
	 */
	private void attack() {
		default_attack = sel_index;
		String s = parent.getBattle().performAction(attacks[sel_index].toLowerCase());
		if(s != null) Game.say(s, "Alert");
		int state = parent.getBattle().checkState();
		if(state == Battle.ENEMY_LOST) {
			key_down = -60;
			exit = true;
		}
	}
	
	/**
	 * Switch to selected menu
	 */
	private void switchPokemon() {
		Game.say("That's enough, " + currentName + ". Go " + pokemon[sel_index] + "!",
				myName);
		parent.getBattle().switchPlayerPokemon(sel_index);
		currentName = pokemon[sel_index];
		attacks = me.getCurrentPokemon().getMoves();
	}
	
	/**
	 * Return to main menu
	 */
	private void returnToMain() {
		state = MAIN;
		strings = mainButtons;
		currentTitle = "What should " + currentName + " do?";
		sel_index = 0;
	}
	
	/**
	 * Perform selection
	 */
	public void select() {
		switch(state) {
		case MAIN: // Currently in main menu
			moveTo(sel_index); // Enter selected menu
			break;
		case SEL_ATTACK:
			attack(); // Perform selected attack
			returnToMain(); // Go back to main menu
			sel_index = 0;
			break;
		case SEL_POKEMON:
			switchPokemon(); // Switch to selected pokemon
			returnToMain(); // Go back to main menu
			sel_index = 0;
			break;
		}
	}
	
	public void exit() {
		returnToMain();
	}
	
	private boolean isBoss() {
		return (parent.getBattle().getOpponent() != null && parent.getBattle().getOpponent() instanceof trainerBoss);
	}
	
	/**
	 * Update the menu
	 */
	public void update() {
		if(isBoss() && parent.getBattle().getOpponent().isBeaten()) {
			win();
			Game.permaWin();
		} else {
			int state = parent.getBattle().checkState();
			if(state == Battle.I_LOST || state == Battle.NORMAL && exit) lose();
			else if(state == Battle.ENEMY_LOST) win();
		}
		super.update();
	}
}